// encoding utf-8
#include <QyDebug.h>
#include "QyRender.h"
#include "QyRenderLayer.h"

using namespace QyRender;

/**************************************************************************************************/

struct SelectRecord {
    GLuint count;
    GLfloat minZ;
    GLfloat maxZ;
    GLuint layerIndex;
    GLuint itemIndex;

    explicit SelectRecord( GLuint *& selectBuffer ) {

        count = *selectBuffer; selectBuffer ++;
        if (!count)
            return;

        if ( count != 2 )
            while ( count >= 0 ) { selectBuffer ++; count--; }

        minZ = GLfloat(*selectBuffer); selectBuffer ++;
        maxZ = GLfloat(*selectBuffer); selectBuffer ++;
        layerIndex = *selectBuffer; selectBuffer ++;
        itemIndex = *selectBuffer; selectBuffer ++;

    }

};

/**************************************************************************************************/

bool compareLayer( const Layer * layer1, const Layer * layer2 ) {

    return layer1->z() < layer2->z();
}

bool compareSelectRecord( const SelectRecord & r1, const SelectRecord & r2 ) {

    return r1.maxZ < r2.maxZ;
}

/**************************************************************************************************/

Painter::Painter() {
}

Painter::~Painter() {
}

ItemList Painter::itemsFromGLSelectBuffer( GLuint * selectBuffer, GLuint length ) const {

    ItemList items;

    if ( selectBuffer && length ) {

        QList<SelectRecord> records;

        for ( GLuint i = 0; i < length; ++i  )
            records.append( SelectRecord(selectBuffer) );

        qSort( records.begin(), records.end(), compareSelectRecord );

        Layer * layer;
        foreach ( SelectRecord record, records ) {

            if ( record.layerIndex >= GLuint( p_layers.count() ) ) {

                qWarning("Selection: layer index out of range");

                continue;
            }

            layer = p_layers[record.layerIndex];

            Q_ASSERT(layer);

            if ( record.itemIndex >= GLuint( layer->items().count() ) ) {

                qWarning("Selection: item index out of range");

                continue;
            }

            items.append( layer->items()[record.itemIndex] );

        }

    }

    return items;
}

void Painter::select() {

    GLuint layerIndex = 0;
    GLuint itemIndex;

    foreach ( Layer * layer, p_layers ) {

        if ( layer->flags() & Layer::Selectable|Layer::Visible ) {

            itemIndex = 0;
            glPushName(layerIndex);

            foreach ( Item * item, layer->items() ) {

                glPushName(itemIndex);
                item->paint(Item::BasicPaint);
                glPopName();
                ++itemIndex;

            }
            glPopName();

        }

        ++ layerIndex;

    }

}

void Painter::paint() {

    foreach ( Layer * layer, p_layers ) {

        if ( layer->flags() & Layer::Visible ) {

            foreach ( Item * item, layer->items() )
                item->paint(Item::DefaultPaint);

        }

    }

}

void Painter::addLayer( Layer * layer ) {

    if ( p_layers.contains(layer) ) // ���� ����� ���� ��� ���� �������
        return;

    if ( layer->painter() != this ) {

        layer->setPainter(this);
        return;
    }

    p_layers.append(layer);
    arrange(); // ��������� ���� �� �������� Z

}

void Painter::removeLayer( Layer * layer ) {

    if ( layer->painter() != this ) {

        layer->setPainter(0);
        return;
    }

    p_layers.removeAll(layer);

}

void Painter::arrange() {

    qSort( p_layers.begin(), p_layers.end(), compareLayer );

}
